﻿using System;
using System.Reflection;

using BizElements.BusinessLayer;

namespace BizElements.Web
{
    /// <summary>
    /// Boolean control property bound to a business object field (see: <see cref="IBindableField"/>).
    /// </summary>
    internal sealed class BooleanPropertyBinder : IControlPropertyBinder
    {
        object trueValue;
        string trueValueText;
        object falseValue;

        #region Contructors.

        /// <summary>
        /// Initializes a new instance of <b>BooleanPropertyBinder</b> class.
        /// </summary>
        public BooleanPropertyBinder()
            : this(true, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of <b>BooleanPropertyBinder</b> class.
        /// </summary>
        /// <param name="trueValue">The value used in bound field instead of <b>true</b>.</param>
        /// <param name="falseValue">The value used in bound field instead of <b>false</b>.</param>
        public BooleanPropertyBinder(object trueValue, object falseValue)
        {
            this.TrueValue = trueValue;
            this.FalseValue = falseValue;
        }

        #endregion

        #region GetValue.

        /// <summary>
        /// Gets the value stored in the control.
        /// </summary>
        /// <param name="control">Control.</param>
        /// <param name="propertyName">Control property.</param>
        /// <param name="dataType">Ignored. Method always return boolean value.</param>
        /// <param name="formatter">Not used.</param>
        /// <param name="errorCode">A value indicating the type of error encountered during parsing.</param>
        /// <returns>Boolean value stored in the control.</returns>
        public object GetValue(IBoundControl control, string propertyName, Type dataType, IMessageFormatter formatter, out ParseError errorCode)
        {
            // No parsing is taking place.
            errorCode = ParseError.AllOk;
            PropertyInfo controlProperty = control.GetType().GetProperty(propertyName);
            bool ctlValue = (bool)controlProperty.GetValue(control, null);
            object fieldValue = (ctlValue) ? this.trueValue : this.falseValue;
            return fieldValue;
        }

        #endregion

        #region SetValue.

        /// <summary>
        /// Sets and display the given value.
        /// </summary>
        /// <param name="control">Control.</param>
        /// <param name="propertyName">Control property.</param>
        /// <param name="val">Value convertible to <b>bool</b> type which is to be displayed by the control.</param>
        /// <param name="formatter">Not used.</param>
        public void SetValue(IBoundControl control, string propertyName, object val, IMessageFormatter formatter)
        {
            bool ctlValue;
            if (val is bool)
                ctlValue = (bool)val;
            else
                ctlValue = (Convert.ToString(val) == this.trueValueText);

            PropertyInfo property = control.GetType().GetProperty(propertyName);
            property.SetValue(control, ctlValue, null);
        }

        #endregion

        #region Properties.

        /// <summary>
        /// Gets or sets the value used in bound field instead of <b>true</b>.
        /// </summary>
        /// <value>A true/yes indicator. Default is <b>true</b>.</value>
        public object TrueValue
        {
            get { return this.trueValue; }
            set
            {
                this.trueValue = value ?? true;
                this.trueValueText = Convert.ToString(this.trueValue);
            }
        }

        /// <summary>
        /// Gets or sets the value used in bound field instead of <b>false</b>.
        /// </summary>
        /// <value>A false/no indicator. Default is <b>false</b>.</value>
        public object FalseValue
        {
            get { return this.falseValue; }
            set { this.falseValue = value ?? false; }
        }

        #endregion
    }
}